.extern RQtop

.set noat

.global swtick
.global hwtick
.global getTickCount
.global forceContextSwitch
.global getStatusRegister
.global setRunningTask
.global getRunningTask

.ent getStatusRegister
getStatusRegister:
	mfc0 $v0, $12, 1
	jr $ra
.end getStatusRegister

.ent getRunningTask
getRunningTask:
	la $v0, runningTask
	lw $v0, 0($v0)
	jr $ra
.end getRunningTask

.ent setRunningTask
setRunningTask:
	la $t0, runningTask
	sw $a0, 0($t0)
	jr $ra
.end setRunningTask

# routine triggers a SW0 interrupt.
.ent forceContextSwitch
forceContextSwitch:
	mfc0 $t0, $13
	ori $t0, 256 # 1 << 8
	mtc0 $t0, $13
	jr $ra
.end forceContextSwitch

.ent getTickCount
getTickCount:
	la $v0, count
	lw $v0, 0($v0)
	jr $ra
.end getTickCount

.ent hwtick
hwtick:
# increment the tickcount
	la $k1, count
	lw $k0, 0($k1)
	addiu $k0, $k0, 1
	sw $k0, 0($k1)
# context switch
	j tick
.end hwtick

.ent swtick
swtick:
# reset Software Interrupt 0
	li $k1, 256 # 1 << 8
	nor $k1, $k1, $zero # ~(1 << 8)
	mfc0 $k0, $13
	and $k0, $k0, $k1
	mtc0 $k0, $13
# context switch
	j tick
.end swtick

.ent tick
tick:
	di

# If there is no running task, we want to save the kernel stack and frame pointers. Other registers
# are hopefully unnecessary. 
	la $k0, runningTask
	lw $k0, 0($k0)
	la $k1, store # get the address to store the kernel stack information
	beq $k0, $zero, tick_save_kernel_state
		sw $1, 4($k0)
		sw $2, 8($k0) # this is space inefficient to be easier to code
		sw $3, 12($k0)
		sw $4, 16($k0)
		sw $5, 20($k0)
		sw $6, 24($k0)
		sw $7, 28($k0)
		sw $8, 32($k0)
		sw $9, 36($k0)
		sw $10, 40($k0)
		sw $11, 44($k0)
		sw $12, 48($k0)
		sw $13, 52($k0)
		sw $14, 56($k0)
		sw $14, 60($k0)
		sw $16, 64($k0)
		sw $17, 68($k0)
		sw $18, 72($k0)
		sw $19, 76($k0)
		sw $20, 80($k0)
		sw $21, 84($k0)
		sw $22, 88($k0)
		sw $23, 92($k0)
		sw $24, 96($k0)
		sw $25, 100($k0)
		sw $29, 116($k0)
		sw $30, 120($k0)
		sw $31, 124($k0)
# save the epc
		mfc0 $t0, $14, 0
		sw $t0, 128($k0)
# retrieve the kernel stack registers
		lw $sp, 0($k1)
		lw $fp, 4($k1)
		j tick_save_state_done
	tick_save_kernel_state: # save the kernel stack registers
		sw $sp, 0($k1)
		sw $fp, 4($k1)
	tick_save_state_done:

	li $a0, 1
	li $a1, 8192
#	jal PORTToggleBits
	nop

# get the next task
	jal RQtop
	nop

	la $t0, runningTask
	sw $v0, 0($t0)
	addu $k0, $v0, $zero
# Clear the interrupt controller for both timer1 and software 0
	la $t0, IFS0CLR
	li $t1, 18
	sw $t1, 0($t0)

	lw $1, 4($k0)
	lw $2, 8($k0) 
	lw $3, 12($k0)
	lw $4, 16($k0)
	lw $5, 20($k0)
	lw $6, 24($k0)
	lw $7, 28($k0)
	lw $8, 32($k0)
	lw $9, 36($k0)
	lw $10, 40($k0)
	lw $11, 44($k0)
	lw $12, 48($k0)
	lw $13, 52($k0)
	lw $14, 56($k0)
	lw $14, 60($k0)
	lw $16, 64($k0)
	lw $17, 68($k0)
	lw $18, 72($k0)
	lw $19, 76($k0)
	lw $20, 80($k0)
	lw $21, 84($k0)
	lw $22, 88($k0)
	lw $23, 92($k0)
	lw $24, 96($k0)
	lw $25, 100($k0)
	lw $29, 116($k0)
	lw $30, 120($k0)
	lw $31, 124($k0)
# restore the epc register
	lw $k1, 128($k0)
	mtc0 $k1, $14, 0

# reset the status register
# I don't know if this actually works, but it ought to
# in fact it seems to make no difference
	li $k1, 0x6
	nor $k1, $k1, $zero
	mfc0 $k0, $12, 0
	and $k0, $k0, $k1
	ori $k0, $k0, 10
	mtc0 $k0, $12, 0

	ei # enable interrupts
	ehb
	eret

.end tick

.section .kdata, "aw", @nobits
store:
	.space 8
count:
	.word 0
runningTask:
	.word 0

